package com.etc.aspect;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.etc.annotation.LogLogin;
import com.etc.common.enums.LoginTypeEnum;
import com.etc.common.enums.UserTypeEnum;
import com.etc.common.exception.SysOperationException;
import com.etc.common.util.DateUtils;
import com.etc.constants.WebConstants;
import com.etc.logManage.service.ILogLoginService;
import com.etc.logManage.vo.LogLoginVO;
import com.etc.user.model.User;

/**
 * @Title: LogLoginAspect.java
 * @Package com.etc.aspect
 * @Description: TODO
 * @author 黄宇
 * @date 2016年3月28日 下午6:18:30
 * @version V1.0
 */
@Aspect
@Component
public class LogLoginAspect {

	Logger log = LoggerFactory.getLogger(LogLoginAspect.class);

	@Autowired
	private ILogLoginService logLoginService;

	/**
	 * Controller层切点
	 */
	@Pointcut("@annotation(com.etc.annotation.LogLogin)")
	public void controllerAspect() {
	}

	/**
	 * 用于记录登录日志，切面必须放在后置通知
	 * 
	 * @param joinPoint
	 */
	@After("controllerAspect()")
	public void afterMethod(JoinPoint joinPoint) {
		LoginTypeEnum loginType = this.getLoginType(joinPoint);
		if(loginType.equals(LoginTypeEnum.LOGIN)){
			saveLogLogin(joinPoint);
		}
	}

	/**
	 * 用于记录退出日志，切面必须放在前置通知
	 * 
	 * @param joinPoint
	 */
	@Before("controllerAspect()")
	public void beforeMethod(JoinPoint joinPoint) {
		LoginTypeEnum loginType = this.getLoginType(joinPoint);
		if(loginType.equals(LoginTypeEnum.EXIT)){
			saveLogLogin(joinPoint);
		}
	}

	/**
	 * 保存登录日志
	 * 
	 * @param joinPoint
	 */
	public void saveLogLogin(JoinPoint joinPoint) {
		try {
			// 获取当前用户
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes()).getRequest();
			HttpSession session = request.getSession();
			User user = (User) session.getAttribute(WebConstants.USER_KEY);
			// 用户ip
			String ip = request.getRemoteAddr();
			// 获取用户类型
			UserTypeEnum userType = this.getUserType(joinPoint);
			// 登录类型
			LoginTypeEnum loginType = this.getLoginType(joinPoint);

			LogLoginVO vo = new LogLoginVO();
			vo.setTllIp(ip);
			vo.setTllTime(DateUtils.getCurrentDate());
			vo.setTsuName(user.getTsuName());
			vo.setTllUserType(userType.getName());
			vo.setTllType(loginType.getName());
			vo.setTllTime(DateUtils.getCurrentDate());

			this.logLoginService.insert(vo);
		} catch (SysOperationException e) {
			log.error(e.getMessage(), e);
		} catch (Exception e) {
			log.error("记录用户登录日志异常!", e);
		}
	}

	/**
	 * @param joinPoint
	 * @return
	 */
	private LoginTypeEnum getLoginType(JoinPoint joinPoint) {
		// 当前请求类的名称
		String targetName = joinPoint.getTarget().getClass().getName();
		// 当前请求方法的名称
		String methodName = joinPoint.getSignature().getName();
		try {
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();

			// 找到当前请求的方法
			for (Method method : methods) {

				if (method.getName().equals(methodName)) {
					// 找到LogLogin注解
					if (method.isAnnotationPresent(LogLogin.class)) {
						LogLogin logLogin = method.getAnnotation(LogLogin.class);
						return logLogin.loginType();
					}
				}
			}
		} catch (Exception e) {
			throw new SysOperationException("记录日志时，获取登录类型失败", e);
		}
		return null;
	}

	/**
	 * 通过注解获取用户类型
	 * 
	 * @param joinPoint
	 * @return
	 */
	private UserTypeEnum getUserType(JoinPoint joinPoint) {
		// 当前请求类的名称
		String targetName = joinPoint.getTarget().getClass().getName();
		// 当前请求方法的名称
		String methodName = joinPoint.getSignature().getName();
		try {
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();

			// 找到当前请求的方法
			for (Method method : methods) {

				if (method.getName().equals(methodName)) {
					// 找到LogLogin注解
					if (method.isAnnotationPresent(LogLogin.class)) {
						LogLogin logLogin = method.getAnnotation(LogLogin.class);
						return logLogin.userType();
					}
				}
			}
		} catch (Exception e) {
			throw new SysOperationException("记录日志时，获取用户类型失败", e);
		}
		return null;
	}

}
